package net.csdn.business.mirror.service.impl.thirdapi;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.domain.mirror.MyGithubDto;
import net.csdn.business.common.domain.request.mirror.ListRepoDTO;
import net.csdn.business.common.domain.vo.mirror.MirrorNameSpaceVO;
import net.csdn.business.common.domain.vo.mirror.MirrorProjectPageVO;
import net.csdn.business.common.domain.vo.mirror.MirrorRepositoryVO;
import net.csdn.business.common.enums.ResultCodeEnum;
import net.csdn.business.common.exception.BusinessException;
import net.csdn.business.mirror.entity.bo.github.UserBO;
import net.csdn.business.mirror.service.ThirdApi;
import net.csdn.business.mirror.utils.HttpUtil;
import net.csdn.business.mirror.utils.StringUtil;
import net.csdn.business.mirror.utils.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class GiteeApiImpl implements ThirdApi {

    // https://gitee.com/api/v5/swagger#/getV5User
    @Value("${giteeApi.userUrl:https://gitee.com/api/v5/user}")
    private String userUrl;

    // https://gitee.com/api/v5/swagger#/getV5UserRepos
    @Value("${giteeApi.userAllReposUrl:https://gitee.com/api/v5/user/repos?sort=updated&direction=desc&per_page=100}")
    private String userAllReposUrl;

    // https://gitee.com/api/v5/swagger#/getV5UserOrgs
    @Value("${giteeApi.userAllOrgsUrl:https://gitee.com/api/v5/user/orgs?access_token=&page=1&per_page=100}")
    private String userAllOrgsUrl;

    // https://gitee.com/api/v5/swagger#/getV5UserNamespaces
    @Value("${giteeApi.userAllNamespacesUrl:https://gitee.com/api/v5/user/namespaces?access_token=&mode=all}")
    private String userAllNamespacesUrl;

    // https://gitee.com/api/v5/swagger#/getV5OrgsOrgRepos
    @Value("${giteeApi.orgAllReposUrl:https://gitee.com/api/v5/orgs/{org}/repos?access_token=&type=all&page=1&per_page=20}")
    private String orgAllReposUrl;

    // https://gitee.com/api/v5/swagger#/getV5ReposOwnerRepo
    @Value("${giteeApi.userRepoUrl:https://gitee.com/api/v5/repos/{repoPath}}")
    private String userRepoUrl;

    @Override
    public UserBO getUser(String token) {
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json;charset=UTF-8");

        Map<String, String> params = new HashMap<>();
        params.put("access_token", token);
        String url = UrlUtil.getNewUrl(userUrl, params);
        String content = HttpUtil.httpRequest(HttpUtil.RequestMethodEnum.GET, url, headers, null, null).getContent();
        UserBO user = JSONUtil.toBean(content, UserBO.class);
        if (Objects.isNull(user) || StringUtils.isEmpty(user.getLogin())) {
            log.error("giteeApi getUser failed: {}", content);
            return null;
        }
        return user;
    }

    @Override
    public void listUserAllRepos(MyGithubDto myGithub, String namespace, Integer page, Integer pageSize) {
        if (StringUtils.isEmpty(myGithub.getToken())) {
            return;
        }
        if (Objects.isNull(page) || page < 1) {
            page = 1;
        }
        if (Objects.isNull(pageSize) || pageSize < 1 || pageSize > 100) {
            pageSize = 100;
        }

        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json;charset=UTF-8");

        Map<String, String> params = new HashMap<>();
        params.put("access_token", myGithub.getToken());
        params.put("page", page.toString());
        params.put("per_page", pageSize.toString());
        String url;
        if (StringUtils.isEmpty(namespace)) {
            url = UrlUtil.getNewUrl(userAllReposUrl, params);
        } else {
            if (namespace.equals(myGithub.getThirdUsername())) {
                params.put("type", "personal");
                url = UrlUtil.getNewUrl(userAllReposUrl, params);
            } else {
                Map<String, Object> parameter = new HashMap<>();
                parameter.put("org", namespace);
                url = UrlUtil.getNewUrl(StringUtil.replace(orgAllReposUrl, parameter), params);
            }
        }
        HttpUtil.Response response = HttpUtil.httpRequest(HttpUtil.RequestMethodEnum.GET, url, headers, null, null, 10000);
        String content = response.getContent();
        int code=response.getCode();
        if(code!=200){
            switch (code){
                case 401:
                case 403:
                    log.error("giteeApi listUserAllRepos namespace: {}, token 无效: {}", namespace, content);
                    throw new BusinessException(ResultCodeEnum.MIRROR_GITHUB_TOKEN_INVALID);
                default:
                    log.error("giteeApi listUserAllRepos namespace: {}, failed reason: {}", namespace, content);
                    break;
            }
            return;
        }
        List<MyGithubDto.Repository> repos = JSONUtil.toList(content, MyGithubDto.Repository.class);
        repos.forEach(repo -> {
            repo.setVisibility(repo.get_private() ? "private" : "public");
            String[] arr = repo.getFullName().split("/");
            repo.setName(arr[arr.length - 1]);
        });
        myGithub.setItems(repos);
        myGithub.setThirdTotalPage(Integer.parseInt(response.getHeaders().getOrDefault("total_page", "0")));
    }

    @Override
    public List<MirrorNameSpaceVO> listUserNamespaces(String token, String thirdUsername) {
        if (StringUtils.isEmpty(token)) {
            throw new BusinessException(ResultCodeEnum.MIRROR_GITHUB_TOKEN_INVALID);
        }
        MyGithubDto myGithub = new MyGithubDto();
        Map<String, String> params = new HashMap<>();
        params.put("access_token", token);
        String url = UrlUtil.getNewUrl(userAllNamespacesUrl, params);

        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json;charset=UTF-8");

        HttpUtil.Response response = HttpUtil.httpRequest(HttpUtil.RequestMethodEnum.GET, url, headers, null, null, 10000);
        String content = response.getContent();
        int code=response.getCode();
        if(code!=200){
            log.error("GithubApi listUserNamespaces  failed reason: {}", content);
            throw new BusinessException(ResultCodeEnum.MIRROR_GITHUB_TOKEN_INVALID);
        }
        List<MirrorNameSpaceVO> namespaces = JSONUtil.toList(content,MirrorNameSpaceVO.class)
                .stream().filter(namespace -> Arrays.asList("group", "personal").contains(namespace.getType())).collect(Collectors.toList());
        return namespaces;
    }

    @Override
    public MyGithubDto.Repository userRepo(String token, String repoPath) {
        Map<String, String> params = null;
        if (StringUtils.isNotEmpty(token)) {
            params = new HashMap<>();
            params.put("access_token", token);
        }
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("repoPath", repoPath);
        String url = UrlUtil.getNewUrl(StringUtil.replace(userRepoUrl, parameter), params);

        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json;charset=UTF-8");
        try {
            HttpUtil.Response response = HttpUtil.httpRequest(HttpUtil.RequestMethodEnum.GET, url, headers, null, null, 10000);
            String content = response.getContent();
            MyGithubDto.Repository repository = JSONUtil.toBean(content, MyGithubDto.Repository.class);
            if (repository.getId() < 1) {
                return null;
            }
            return repository;
        } catch (Exception e) {
            log.error("giteeApi userRepo error: ", e);
            return null;
        }
    }

    @Override
    public MirrorProjectPageVO getALlRepos(ListRepoDTO repoDTO) throws Exception{
        String token = repoDTO.getToken();
        String namespace=repoDTO.getNamespace();
        String thirdUserName=repoDTO.getThirdUserName();
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(ResultCodeEnum.MIRROR_GITHUB_TOKEN_INVALID);
        }
        Integer page=repoDTO.getPage();
        Integer pageSize=repoDTO.getPageSize();
        if (page==null|| page < 1) {
            page = 1;
        }
        if (pageSize==null || pageSize < 1 || pageSize > 100) {
            pageSize = 100;
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json;charset=UTF-8");
        Map<String, String> params = new HashMap<>();
        params.put("access_token", repoDTO.getToken());
        params.put("page", page.toString());
        params.put("per_page", pageSize.toString());
        String url;
        if (StringUtils.isEmpty(namespace)) {
            url = UrlUtil.getNewUrl(userAllReposUrl, params);
        } else {
            if (namespace.equals(thirdUserName)) {
                params.put("type", "personal");
                url = UrlUtil.getNewUrl(userAllReposUrl, params);
            } else {
                Map<String, Object> parameter = new HashMap<>();
                parameter.put("org", namespace);
                url = UrlUtil.getNewUrl(StringUtil.replace(orgAllReposUrl, parameter), params);
            }
        }
        HttpUtil.Response response = HttpUtil.httpRequest(HttpUtil.RequestMethodEnum.GET, url, headers, null, null, 10000);
        String content = response.getContent();
        int code=response.getCode();
        if(code!=200){
            log.error("giteeApi listUserAllRepos namespace: {}, failed reason: {}", namespace, content);
            throw new BusinessException(ResultCodeEnum.MIRROR_GITHUB_TOKEN_INVALID);
        }
        MirrorProjectPageVO result = new MirrorProjectPageVO();
        List<MirrorRepositoryVO> repos = JSONUtil.toList(content, MirrorRepositoryVO.class);
        repos.forEach(repo -> {
            repo.setVisibility(repo.get_private() ? "private" : "public");
            String[] arr = repo.getFullName().split("/");
            repo.setName(arr[arr.length - 1]);
        });
        result.setTotalPage(Integer.parseInt(response.getHeaders().getOrDefault("total_page", "0")));
        result.setItems(repos);
        return result;
    }
}
